﻿using System;
using System.Globalization;

namespace ContractManager.Common.Class
{
    public static class ClsDateUtils
    {
        #region DayBegin
        /// <summary>
        /// Beginning of Day. Earliest datetime for current date
        /// </summary>
        /// <returns>DateTime</returns>
        public static DateTime DayBegin()
        {
            return DayBegin(DateTime.Now);
        }

        /// <summary>
        /// Beginning of Day. Earliest datetime for <b>date</b>
        /// </summary>
        /// <param name="date">Date value to convert</param>
        /// <returns>new datetime value</returns>
        public static DateTime DayBegin(DateTime date)
        {
            return new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, 0);
        }

        #endregion DayBegin

        #region DayEnd
        /// <summary>
        /// End of Day. Return last datetime for current date.  23:59:59.800
        /// </summary>
        /// <returns>Datetime</returns>
        public static DateTime DayEnd()
        {
            return DayEnd(DateTime.Now);
        }

        /// <summary>
        /// End of Day. Return latest datetime for <b>date</b>
        /// </summary>
        /// <param name="date">Date to change into last datetime</param>
        /// <returns>new datetime value</returns>
        public static DateTime DayEnd(DateTime date)
        {
            return new DateTime(date.Year, date.Month, date.Day, 23, 59, 59, 990);
        }
        #endregion DayEnd


        #region WeekBegin
        /// <summary>
        /// Returns the first day of week based on current date. Week starts on Sunday
        /// </summary>
        /// <returns>Date for first day of week</returns>
        public static DateTime WeekBegin()
        {
            return WeekBegin(DayOfWeek.Sunday);
        }

        /// <summary>
        /// Returns the first day of week based on current date based on defined day of week.
        /// </summary>
        /// <param name="firstDayOfWeek">First day of week</param>
        /// <returns>Date for first day of week</returns>
        public static DateTime WeekBegin(DayOfWeek firstDayOfWeek)
        {
            return WeekBegin(DateTime.Now, firstDayOfWeek);
        }

        /// <summary>
        /// Returns first day of week based on date.  Sunday is first day.
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <returns>Date for first day of week</returns>
        public static DateTime WeekBegin(DateTime date)
        {
            return WeekBegin(date, DayOfWeek.Sunday);
        }

        /// <summary>
        /// Returns first day of week based on date using arbitrary first day of week
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstDayOfWeek">First day of week</param>
        /// <returns>Date for first day of week</returns>
        public static DateTime WeekBegin(DateTime date, DayOfWeek firstDayOfWeek)
        {
            return WeekEnd(date, firstDayOfWeek).AddDays(-7);
        }
        #endregion WeekBegin


        #region WeekEnd
        /// <summary>
        /// End of Week. Returns the last day of the week for the current date
        /// </summary>
        /// <returns>datetime</returns>
        /// <remarks>Weeks are defined Sunday-Saturday</remarks>
        public static DateTime WeekEnd()
        {
            return WeekEnd(DayOfWeek.Sunday);
        } //WeekEnd()

        /// <summary>
        /// Returns the last day of the week for the current date.
        /// </summary>
        /// <param name="firstDayOfWeek">Day for start of week.  Often Sunday or Monday</param>
        /// <returns>Date for last day of week</returns>
        public static DateTime WeekEnd(DayOfWeek firstDayOfWeek)
        {
            return WeekEnd(DateTime.Now, firstDayOfWeek);
        }
        /// <summary>
        /// Returns the last day of the week.
        /// </summary>
        /// <param name="firstDayOfWeek">Day for start of week.  Often Sunday or Monday</param>
        /// <param name="date">Date to check</param>
        /// <returns>Date for last day of week</returns>
        public static DateTime WeekEnd(DateTime date, DayOfWeek firstDayOfWeek)
        {
            int delta = 0;
            switch (date.DayOfWeek)
            {
                case DayOfWeek.Sunday: delta = 6; break;
                case DayOfWeek.Monday: delta = 5; break;
                case DayOfWeek.Tuesday: delta = 4; break;
                case DayOfWeek.Wednesday: delta = 3; break;
                case DayOfWeek.Thursday: delta = 2; break;
                case DayOfWeek.Friday: delta = 1; break;
                case DayOfWeek.Saturday: delta = 0; break;
            }
            return DayEnd(date.AddDays(delta));
        }

        /// <summary>
        /// Returns the last day of the week for which <b>date</b> is part. Week starts on Sunday.
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <returns>Date for last day of week.</returns>
        public static DateTime WeekEnd(DateTime date)
        {
            return WeekEnd(date, DayOfWeek.Sunday);
        } //WeekEnd()
        #endregion WeekEnd


        #region MonthBegin
        /// <summary>
        /// Gets first day for calendar Month for current date. Note: Returns date with 00:00:00.000 time component
        /// </summary>
        /// <returns>First day of month</returns>
        public static DateTime MonthBegin()
        {
            return MonthBegin(DateTime.Now);
        }

        /// <summary>
        /// Gets first day of Month for calendar Month for a specific <paramref name="date"/> Note: Returns date with 00:00:00.000 time component
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <returns>First day of month</returns>
        public static DateTime MonthBegin(DateTime date)
        {
            return new DateTime(date.Year, date.Month, 1, 0, 0, 0);
        }

        public static DateTime GetFirstDayOfMonth(int iMonth, int iYear)
        {
            DateTime dtFrom = new DateTime(iYear, iMonth, 1);

            dtFrom = dtFrom.AddDays(-(dtFrom.Day - 1));

            
            return dtFrom;
        }

        public static DateTime GetLastDayOfMonth(int iMonth, int iYear)
        {

            DateTime dtTo = new DateTime(iYear, iMonth, 1);

            dtTo = dtTo.AddMonths(1);

            dtTo = dtTo.AddDays(-(dtTo.Day));

            
            return dtTo;

        }

        #endregion

        #region MonthEnd
        /// <summary>
        /// End of Month for current date().  Note: Returns date with 23:59:59.800 time component
        /// </summary>
        /// <returns>Latest datetime for current month</returns>
        public static DateTime MonthEnd()
        {
            return MonthEnd(DateTime.Now);

        } //MonthEnd()

        /// <summary>
        /// End of Month MonthEnd()  Note: Returns date with 23:59:59.999 time component
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <returns>Latest datetime for month</returns>
        public static DateTime MonthEnd(DateTime date)
        {
            return new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month), 23, 23, 59, 999);
        } //MonthEnd()


        /// <summary>
        /// Determines if a value is a weekendday (Saturday,Sunday)
        /// </summary>
        /// <param name="date">Date to evaluate</param>
        /// <returns>True if date is weekendday (Saturday,Sunday)</returns>
        public static bool IsWeekEndDay(DateTime date)
        {
            return !IsWeekDay(date);
        }

        /// <summary>
        /// Determines if a value is a weekday (Monday-Friday)
        /// </summary>
        /// <param name="date">Date to evaluate</param>
        /// <returns>True if date is weekday (Monday-Friday)</returns>
        public static bool IsWeekDay(DateTime date)
        {
            if (date.DayOfWeek == DayOfWeek.Sunday || date.DayOfWeek == DayOfWeek.Saturday)
                return false;
            return true;
        }
        #endregion MonthEnd


        #region QuarterBegin
        /// <summary>
        /// Beginning of Quarter. Get earliest datetime value for <paramref name="quarter"/> for year starting in January
        /// </summary>
        /// <param name="quarter">Quarter number (1-4)</param>
        /// <returns>First date in quarter</returns>
        public static DateTime QuarterBegin(int quarter)
        {
            return QuarterBegin(quarter, DateTime.Now, SNetMonth.January);
        }

        /// <summary>
        /// Beginning of Quarter.  Get earliest date for <paramref name="quarter"/> with year starting in <paramref name="firstMonthOfYear"/>
        /// </summary>
        /// <param name="quarter">Quarter to get</param>
        /// <param name="dateInYear">Random date in year that quarter will belong to.  Used to determine correct returned year</param>
        /// <param name="firstMonthOfYear">First Month of year. (Often fiscal year)</param>
        /// <returns>First date in quarter</returns>
        public static DateTime QuarterBegin(int quarter, DateTime dateInYear, SNetMonth firstMonthOfYear)
        {
            return QuarterBegin(quarter, dateInYear, new DateTime(DateTime.MinValue.Year, monthToInt(firstMonthOfYear), 1));
        }

        /// <summary>
        /// Beginning date of a specific quarter. Get earliest date for <paramref name="quarter"/> with year starting in <paramref name="firstDayOfYear"/>
        /// </summary>
        /// <param name="quarter">Quarter to return starting date for</param>
        /// <param name="dateInYear">Random date in year that quarter will belong to.  Used to determine correct returned year</param>
        /// <param name="firstDayOfYear">Date calendar starts. Year component ignored</param>
        /// <returns>DateTime of first day quarter begins</returns>
        public static DateTime QuarterBegin(int quarter, DateTime dateInYear, DateTime firstDayOfYear)
        {
            DateTime dte = YearBegin(dateInYear, firstDayOfYear);
            dte = dte.AddMonths((quarter - 1) * 3);
            return dte;
        }

        /// <summary>
        /// Returns the first date of a quarter for a particular date
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <returns>DateTime of first day of quarter</returns>
        public static DateTime QuarterBegin(DateTime date)
        {
            return QuarterBegin(date, SNetMonth.January);
        }

        /// <summary>
        /// Returns the first date of a current quarter for the current date for year beginning in January
        /// </summary>
        /// <returns>DateTime of first day of quarter</returns>
        public static DateTime QuarterBegin()
        {
            return QuarterBegin(DateTime.Now, SNetMonth.January);
        }

        /// <summary>
        /// Returns the first date of current quarter for the current date for year beginning in <paramref name="firstMonthOfYear"/>
        /// </summary>
        /// <param name="firstMonthOfYear">First Month of year. (Often fiscal)</param>
        /// <returns>Date of first Month of year</returns>
        public static DateTime QuarterBegin(SNetMonth firstMonthOfYear)
        {
            return QuarterBegin(DateTime.Now, firstMonthOfYear);
        }

        /// <summary>
        /// Returns the first date of the quarter of <paramref name="date"/> for year beginning in <paramref name="firstMonthOfYear"/>
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstMonthOfYear">First Month of year. (Often fiscal)</param>
        /// <returns>Date of first part of quarter</returns>
        public static DateTime QuarterBegin(DateTime date, SNetMonth firstMonthOfYear)
        {
            return QuarterBegin(date, new DateTime(DateTime.MinValue.Year, monthToInt(firstMonthOfYear), 1));
        }

        /// <summary>
        /// Returns the first date for the quarter for <paramref name="date"/> for year beginning in <paramref name="firstDayOfYear"/>
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstDayOfYear">First day of year. (Often fiscal)</param>
        /// <returns>Date of first day in quarter</returns>
        public static DateTime QuarterBegin(DateTime date, DateTime firstDayOfYear)
        {
            DateTime qBegin = YearBegin(date, firstDayOfYear); //Jan=1
            DateTime qEnd = MonthEnd(qBegin.AddMonths(3)); //Mar=3

            for (int quarter = 1; quarter <= 4; quarter++)
            {
                if (qBegin <= date && date <= qEnd)
                {
                    return qBegin;
                }
                qBegin = qBegin.AddMonths(3);
                qEnd = MonthEnd(qBegin.AddMonths(3));
            }
            throw new NotImplementedException("Unable to find quarter start for date");
        }
        #endregion QuarterBegin


        #region QuarterEnd
        /// <summary>
        /// End of Quarter QuarterEnd()
        /// </summary>
        /// <returns>Last datetime value for current quarter</returns>
        public static DateTime QuarterEnd()
        {
            return QuarterEnd(DateTime.Now.Date, SNetMonth.January);
        }

        /// <summary>
        /// Get last date of quarter with year starting on <paramref name="firstMonthOfYear"/>
        /// </summary>
        /// <param name="firstMonthOfYear">First Month of year. (Often fiscal)</param>
        /// <returns>First date of quarter</returns>
        public static DateTime QuarterEnd(SNetMonth firstMonthOfYear)
        {
            return QuarterEnd(DateTime.Now, firstMonthOfYear);
        }

        /// <summary>
        /// End of Quarter for a date for year starting in January
        /// </summary>
        /// <param name="date">Date which is part of a quarter</param>
        /// <returns>last datetime value for quarter</returns>
        public static DateTime QuarterEnd(DateTime date)
        {
            return QuarterEnd(date, SNetMonth.January);
        } //QuarterEnd

        /// <summary>
        /// End of current quarter of <paramref name="date"/> for year starting in <paramref name="firstMonthOfYear"/>
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstMonthOfYear">First Month in year. (Often fiscal year)</param>
        /// <returns>Last date in quarter</returns>
        public static DateTime QuarterEnd(DateTime date, SNetMonth firstMonthOfYear)
        {
            return QuarterEnd(date, new DateTime(DateTime.MinValue.Year, monthToInt(firstMonthOfYear), 1));

        }
        /// <summary>
        /// End of quarter for year beginning in January
        /// </summary>
        /// <param name="quarter">Quarter to find</param>
        /// <returns>Last date of quarter</returns>
        public static DateTime QuarterEnd(int quarter)
        {
            return QuarterEnd(quarter, DateTime.Now, SNetMonth.January);
        }

        /// <summary>
        /// Get last date in quarter for year beginning on <paramref name="firstMonthOfYear"/>
        /// </summary>
        /// <param name="quarter">Quarter to check</param>
        /// <param name="dateInYear">Random date in year that quarter will belong to.  Used to determine correct returned year</param>
        /// <param name="firstMonthOfYear">First Month of year.  (Often fiscal)</param>
        /// <returns>DateTime of last day in quarter</returns>
        public static DateTime QuarterEnd(int quarter, DateTime dateInYear, SNetMonth firstMonthOfYear)
        {
            return QuarterEnd(quarter, dateInYear, new DateTime(DateTime.MinValue.Year, monthToInt(firstMonthOfYear), 1));
        }

        /// <summary>
        /// Get last date in quarter for year beginning on <paramref name="firstDayOfYear"/>
        /// </summary>
        /// <param name="quarter">Quarter to check</param>
        /// <param name="dateInYear">Random date in year that quarter will belong to.  Used to determine correct returned year</param>
        /// <param name="firstDayOfYear">Day year starts.</param>
        /// <returns>DateTime of last day in quarter</returns>
        public static DateTime QuarterEnd(int quarter, DateTime dateInYear, DateTime firstDayOfYear)
        {
            DateTime dte = QuarterBegin(quarter, dateInYear, firstDayOfYear);
            dte = dte.AddMonths(2);
            dte = MonthEnd(dte);
            return dte;
        }

        /// <summary>
        /// Returns the last date for the quarter for <paramref name="date"/> for year beginning in <paramref name="firstDayOfYear"/>
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstDayOfYear">First day of year. (Often fiscal)</param>
        /// <returns>Date of last day in quarter</returns>
        public static DateTime QuarterEnd(DateTime date, DateTime firstDayOfYear)
        {
            DateTime qBegin = YearBegin(date, firstDayOfYear); //Jan=1
            DateTime qEnd = MonthEnd(qBegin.AddMonths(2)); //Mar=3

            for (int quarter = 1; quarter <= 4; quarter++)
            {
                if (qBegin <= date && date <= qEnd)
                {
                    return qEnd;
                }
                qBegin = qBegin.AddMonths(3);
                qEnd = MonthEnd(qBegin.AddMonths(2));
            }
            throw new ArgumentException("Unable to find Quarter End For Quarter");
        }
        #endregion QuarterEnd


        #region YearBegin
        /// <summary>
        /// Get first day of year for current datetime with year starting in January
        /// </summary>
        /// <returns>DateTime for first day of year</returns>
        public static DateTime YearBegin()
        {
            return YearBegin(DateTime.Now, SNetMonth.January);
        }

        /// <summary>
        /// Get first day of year for current datetime with year starting in <paramref name="firstMonthOfYear"/>
        /// </summary>
        /// <param name="firstMonthOfYear">First Month of year (Often fiscal)</param>
        /// <returns>Date of first day of year</returns>
        public static DateTime YearBegin(SNetMonth firstMonthOfYear)
        {
            return YearBegin(DateTime.Now, firstMonthOfYear);
        }

        /// <summary>
        /// Get first day of year for <paramref name="date"/> for year beginning in January
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <returns>Date of first day of year</returns>
        public static DateTime YearBegin(DateTime date)
        {
            return YearBegin(date, SNetMonth.January);
        }

        /// <summary>
        /// Get first day of year for <paramref name="date"/> for year beginning on <paramref name="firstMonthOfYear"/>
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstMonthOfYear">First Month of year (Often fiscal)</param>
        /// <returns>Date of first day of year</returns>
        public static DateTime YearBegin(DateTime date, SNetMonth firstMonthOfYear)
        {
            return YearBegin(date, new DateTime(DateTime.MinValue.Year, monthToInt(firstMonthOfYear), 1));
        }

        /// <summary>
        /// Get first day of year for <paramref name="date"/> for year beginning on <paramref name="firstDayOfYear"/>
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstDayOfYear">Day year begins on (Often fiscal)</param>
        /// <returns>First date of year</returns>
        public static DateTime YearBegin(DateTime date, DateTime firstDayOfYear)
        {
            if (date.Month >= firstDayOfYear.Month)
            {
                return MonthBegin(new DateTime(date.Year, firstDayOfYear.Month, firstDayOfYear.Day));
            }
            //----------------------------------------------------------
            // <date> is near end of year
            //----------------------------------------------------------
            if (date.Month < firstDayOfYear.Month)
            {
                int year = date.Year - 1;
                return MonthBegin(new DateTime(year, firstDayOfYear.Month, firstDayOfYear.Day));
            }
            throw new ArgumentException("Unable to calculate YearBegin");
        }


        #endregion

        #region YearEnd
        /// <summary>
        /// Get last day of year for current datetime with year starting in January
        /// </summary>
        /// <returns>DateTime for last day of year</returns>
        public static DateTime YearEnd()
        {
            return YearEnd(DateTime.Now, SNetMonth.January);
        }

        /// <summary>
        /// Get last day of year for current datetime with year starting in <paramref name="firstMonthOfYear"/>
        /// </summary>
        /// <param name="firstMonthOfYear">last Month of year (Often fiscal)</param>
        /// <returns>Date of last day of year</returns>
        public static DateTime YearEnd(SNetMonth firstMonthOfYear)
        {
            return YearEnd(DateTime.Now, firstMonthOfYear);
        }

        /// <summary>
        /// Get last day of year for <paramref name="date"/> for year beginning in January
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <returns>Date of last day of year</returns>
        public static DateTime YearEnd(DateTime date)
        {
            return YearEnd(date, SNetMonth.January);
        }

        /// <summary>
        /// Get last day of year for <paramref name="date"/> for year beginning on <paramref name="firstMonthOfYear"/>
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstMonthOfYear">First day of year (Often fiscal)</param>
        /// <returns>Date of last day of year</returns>
        public static DateTime YearEnd(DateTime date, SNetMonth firstMonthOfYear)
        {
            DateTime yearBegin = YearBegin(date, firstMonthOfYear);
            return YearEnd(date, yearBegin);
        }

        /// <summary>
        /// Get last day of year for <paramref name="date"/> for year beginning on <paramref name="firstDayOfYear"/>
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstDayOfYear">Month/Day year begins on (Often fiscal)</param>
        /// <returns>Last date of year</returns>
        public static DateTime YearEnd(DateTime date, DateTime firstDayOfYear)
        {
            DateTime dte = YearBegin(date, firstDayOfYear); //(2/13/2007,4/1/2006)=> 4/1/2006
            dte = dte.AddYears(1); //[4/1/2007]
            dte = YearBegin(dte, firstDayOfYear).AddDays(-1); // [3/31/2007]
            return MonthEnd(dte); // [3/31/2007 23:59:50.800]
        }


        #region DatePart
        #region DayOfYear
        /// <summary>
        /// Return the day of year for current date/time based on 1/1 calendar
        /// </summary>
        /// <returns></returns>
        public static int DayOfYear()
        {
            return DateTime.Now.DayOfYear;
        }

        /// <summary>
        /// Return the day of year for <paramref name="date"/> where calendar begins on <paramref name="firstDayOfYear"/>
        /// </summary>
        /// <param name="date">Date to calculate for</param>
        /// <param name="firstDayOfYear">First day of calendar year</param>
        /// <returns>The total number of days since the first of the year</returns>
        public static int DayOfYear(DateTime date, DateTime firstDayOfYear)
        {
            DateTime dte = YearBegin(date, firstDayOfYear);
            TimeSpan ts = date.Subtract(dte);
            return ts.Days;
        }

        /// <summary>
        /// Return a particular day of year with a calendar beginning on <paramref name="firstDayOfYear"/>
        /// </summary>
        /// <param name="day">Day number to get</param>
        /// <param name="dateInYear">Random date in year to use for calculating correct year</param>
        /// <param name="firstDayOfYear">First day in calendar. Year component is ignored</param>
        /// <returns>DateTime of a particular day of year</returns>
        public static DateTime DayOfYear(int day, DateTime dateInYear, DateTime firstDayOfYear)
        {
            DateTime dte = YearBegin(dateInYear, firstDayOfYear);
            return dte.AddDays(day);
        }
        #endregion DayOfYear

        #region Month
        /// <summary>
        /// Return Month of year for current date/time based on 1/1 calendar
        /// </summary>
        /// <returns>Current month</returns>
        public static int Month()
        {
            return DateTime.Now.Month;
        }

        /// <summary>
        /// Return Month of year for <paramref name="date"/> based on calendar beginning on <paramref name="firstDayOfYear"/>
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstDayOfYear">First day of calendar year</param>
        /// <returns>Current Month for year</returns>
        public static int Month(DateTime date, DateTime firstDayOfYear)
        {
            DateTime dteCounter = YearBegin(date, firstDayOfYear);
            DateTime endDate = MonthEnd(date);
            int month = 1;
            for (; dteCounter <= endDate; month++)
            {
                if (dteCounter >= endDate)
                    return month;
                dteCounter = dteCounter.AddMonths(1);
            }
            return month - 1;

        }

        /// <summary>
        /// Return first day of Month based on calendar beginning on <paramref name="firstDayOfYear"/>
        /// </summary>
        /// <param name="month">Month number to get</param>
        /// <param name="dateInYear">Random date in year to use for calculating correct year</param>
        /// <param name="firstDayOfYear">First day in calendar. Year component is ignored</param>
        /// <returns>DateTime of first day of month</returns>
        public static DateTime Month(int month, DateTime dateInYear, DateTime firstDayOfYear)
        {
            DateTime dte = YearBegin(dateInYear, firstDayOfYear);
            return dte.AddMonths(month - 1);
        }
        #endregion Month

        #region Quarter
        /// <summary>
        /// Return the calendar quarter for the current date for year starting in January
        /// </summary>
        /// <returns>Quarter number (1-4) for current date</returns>
        public static int Quarter()
        {
            return Quarter(DateTime.Now.Date);
        }

        /// <summary>
        /// Return the calendar quarter for the current date for year starting in <paramref name="firstMonthOfYear"/>
        /// </summary>
        /// <param name="firstMonthOfYear">First of of year. (Often fiscal year)</param>
        /// <returns>Quarter number (1-4) for current date</returns>
        public static int Quarter(SNetMonth firstMonthOfYear)
        {
            return Quarter(DateTime.Now, firstMonthOfYear);
        }

        /// <summary>
        /// Return the calendar quarter for a specific date
        /// </summary>
        /// <param name="date">datetime to check</param>
        /// <returns>Quarter number (1-4) for <b>date</b></returns>
        public static int Quarter(DateTime date)
        {
            return Quarter(date, SNetMonth.January);
        } //Quarter

        /// <summary>
        /// Return the calendar quarter for a specific date for year that begins on a specific month
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstMonthOfYear">First Month of year. (Often fiscal year)</param>
        /// <returns>Quarter number (1-4) for current date</returns>
        public static int Quarter(DateTime date, SNetMonth firstMonthOfYear)
        {
            return Quarter(date, new DateTime(date.Year, monthToInt(firstMonthOfYear), 1));
        }

        /// <summary>
        /// Return the calendar quarter for a specific date for year that begins on <paramref name="firstDayOfYear"/>
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstDayOfYear">First day of year (Often fiscal)</param>
        /// <returns>Quarter number (1-4) for current date</returns>
        /// <remarks>Note:  firstDayofYear is assumed to begin at the beginning of month</remarks>
        public static int Quarter(DateTime date, DateTime firstDayOfYear)
        {
            DateTime qBegin = YearBegin(date, firstDayOfYear); //Jan=1
            DateTime qEnd = MonthEnd(qBegin.AddMonths(2)); //Mar=3

            for (int quarter = 1; quarter <= 4; quarter++)
            {
                if (qBegin <= date && date <= qEnd)
                    return quarter;
                qBegin = qBegin.AddMonths(3);
                qEnd = MonthEnd(qBegin.AddMonths(2));
            }
            throw new ArgumentException("Unable to find quarter for date");
        }

        #endregion Quarter

        #region Year
        /// <summary>
        /// Return year for current date/time based on 1/1 calendar
        /// </summary>
        /// <returns>Current year</returns>
        public static int Year()
        {
            return DateTime.Now.Year;
        }

        /// <summary>
        /// Return year for <paramref name="date"/> base on calendar beginning on <paramref name="firstDayOfYear"/>
        /// </summary>
        /// <param name="date">Date to check</param>
        /// <param name="firstDayOfYear">First day of calendar year</param>
        /// <returns>Year component of last calendar day of year</returns>
        public static int Year(DateTime date, DateTime firstDayOfYear)
        {
            return YearEnd(date, firstDayOfYear).Year;
        }

        #endregion Year
        #endregion DatePart


        private static int monthToInt(SNetMonth month)
        {
            return (int)month;
        }
        /// <summary>
        /// Month numbers.  Used when system begin counting month numbers from 0 instead of 1
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue")]
        public enum SNetMonth
        {
            /// <summary>
            /// January
            /// </summary>
            January = 1,

            /// <summary>
            /// February
            /// </summary>
            February = 2,

            /// <summary>
            /// March
            /// </summary>
            March = 3,

            /// <summary>
            /// April
            /// </summary>
            April = 4,

            /// <summary>
            /// May
            /// </summary>
            May = 5,

            /// <summary>
            /// June
            /// </summary>
            June = 6,

            /// <summary>
            /// July
            /// </summary>
            July = 7,

            /// <summary>
            /// August
            /// </summary>
            August = 8,

            /// <summary>
            /// September
            /// </summary>
            September = 9,

            /// <summary>
            /// October
            /// </summary>
            October = 10,

            /// <summary>
            /// November
            /// </summary>
            November = 11,

            /// <summary>
            /// December
            /// </summary>
            December = 12
        }


        #endregion


        #region "Get Week Number From Date"
        /// <summary>Get the week number of a certain date, provided that
        /// the first day of the week is Monday, the first week of a year
        /// is the one that includes the first Thursday of that year and
        /// the last week of a year is the one that immediately precedes
        /// the first calendar week of the next year.
        /// </summary>
        /// <param name="date">Date of interest.</param>
        /// <returns>The week number.</returns>
        public static int GetWeekNumber(this DateTime date)
        {
            //Constants
            const int jan = 1;
            const int dec = 12;
            const int lastdayofdec = 31;
            const int firstdayofjan = 1;
            const int thursday = 4;

            //Get the day number since the beginning of the year
            int dayOfYear = date.DayOfYear;

            //Get the first and last weekday of the year
            int startWeekDayOfYear = (int)(new DateTime(date.Year, jan, firstdayofjan)).DayOfWeek;
            int endWeekDayOfYear = (int)(new DateTime(date.Year, dec, lastdayofdec)).DayOfWeek;

            //Compensate for using monday as the first day of the week
            if (startWeekDayOfYear == 0)
                startWeekDayOfYear = 7;
            if (endWeekDayOfYear == 0)
                endWeekDayOfYear = 7;


            int daysInFirstWeek = 8 - (startWeekDayOfYear);


            //if (startWeekDayOfYear == thursday || endWeekDayOfYear == thursday)
            //    thursdayFlag = true;


            int fullWeeks = (int)Math.Ceiling((dayOfYear - (daysInFirstWeek)) / 7.0);
            int resultWeekNumber = fullWeeks;


            if (daysInFirstWeek >= thursday)
                resultWeekNumber = resultWeekNumber + 1;


            //if (resultWeekNumber > 52 && !thursdayFlag)
            //    resultWeekNumber = 1;


            if (resultWeekNumber == 0)
                resultWeekNumber = GetWeekNumber(new DateTime(date.Year - 1, dec, lastdayofdec));
            return resultWeekNumber;
        }

        public static int WeeksInYear(int year)
        {
            GregorianCalendar cal = new GregorianCalendar(GregorianCalendarTypes.Localized);
            return cal.GetWeekOfYear(new DateTime(year, 12, 28), CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
        }

        public static int WeekNumber(DateTime date)
        {
            GregorianCalendar cal = new GregorianCalendar(GregorianCalendarTypes.Localized);
            return cal.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
        }

        public static int NumberOfWeeks(DateTime dateFrom, DateTime dateTo)
        {
            TimeSpan Span = dateTo.Subtract(dateFrom);

            if (Span.Days <= 7)
            {
                if (dateFrom.DayOfWeek > dateTo.DayOfWeek)
                {
                    return 2;
                }

                return 1;
            }

            int days = Span.Days - 7 + (int)dateFrom.DayOfWeek;
            int weekCount = 1;
            int dayCount = 0;

            for (weekCount = 1; dayCount < days; weekCount++)
            {
                dayCount += 7;
            }

            return weekCount;
        }
        #endregion


        #region "Date Helper"
        public static DateTime DayOfMonth(DateTime time, bool firstDay)
        {
            DateTime time1 = new DateTime(time.Year, time.Month, 1);
            return firstDay ? time1 : time1.AddMonths(1).AddDays(-1);
        }

        public static DateTime DayOfQuarter(DateTime time, bool firstDay)
        {
            int m = 0;
            switch (time.Month)
            {
                case 1:
                case 2:
                case 3:
                    m = 1; break;
                case 4:
                case 5:
                case 6:
                    m = 4; break;
                case 7:
                case 8:
                case 9:
                    m = 7; break;
                case 10:
                case 11:
                case 12:
                    m = 11; break;
            }

            DateTime time1 = new DateTime(time.Year, m, 1);
            return firstDay ? time1 : time1.AddMonths(3).AddDays(-1);
        }

        public static DateTime DayOfYear(DateTime time, bool firstDay)
        {
            return firstDay ? new DateTime(time.Year, 1, 1) : new DateTime(time.Year, 12, 31);
        }

        public static string GetDate(string datetimestr, string replacestr)
        {
            if (datetimestr == null)
            {
                return replacestr;
            }

            if (datetimestr.Equals(""))
            {
                return replacestr;
            }

            try
            {
                datetimestr = Convert.ToDateTime(datetimestr).ToString("yyyy-MM-dd").Replace("1900-01-01", replacestr);
            }
            catch
            {
                return replacestr;
            }
            return datetimestr;

        }

        public static string GetDateTime(int relativeday)
        {
            return DateTime.Now.AddDays(relativeday).ToString("yyyy-MM-dd HH:mm:ss");
        }

        public static string GetStandardDateTime(string fDateTime, string formatStr)
        {
            if (fDateTime == "0000-0-0 0:00:00")
            {

                return fDateTime;
            }
            DateTime s = Convert.ToDateTime(fDateTime);
            return s.ToString(formatStr);
        }

        public static string GetStandardDateTime(string fDateTime)
        {
            return GetStandardDateTime(fDateTime, "yyyy-MM-dd HH:mm:ss");
        }

        public static int StrDateDiffSeconds(string Time, int Sec)
        {
            TimeSpan ts = DateTime.Now - DateTime.Parse(Time).AddSeconds(Sec);
            if (ts.TotalSeconds > int.MaxValue)
            {
                return int.MaxValue;
            }
            else if (ts.TotalSeconds < int.MinValue)
            {
                return int.MinValue;
            }
            return (int)ts.TotalSeconds;
        }

        public static int StrDateDiffMinutes(string time, int minutes)
        {
            if (time == "" || time == null)
                return 1;
            TimeSpan ts = DateTime.Now - DateTime.Parse(time).AddMinutes(minutes);
            if (ts.TotalMinutes > int.MaxValue)
            {
                return int.MaxValue;
            }
            else if (ts.TotalMinutes < int.MinValue)
            {
                return int.MinValue;
            }
            return (int)ts.TotalMinutes;
        }


        public static int StrDateDiffHours(string time, int hours)
        {
            if (time == "" || time == null)
                return 1;
            TimeSpan ts = DateTime.Now - DateTime.Parse(time).AddHours(hours);
            if (ts.TotalHours > int.MaxValue)
            {
                return int.MaxValue;
            }
            else if (ts.TotalHours < int.MinValue)
            {
                return int.MinValue;
            }
            return (int)ts.TotalHours;
        }

        public static int GetDaysOfYear(int iYear)
        {
            return IsRuYear(iYear) ? 366 : 365;
        }

        public static int GetDaysOfYear(DateTime dt)
        {
            return IsRuYear(dt.Year) ? 366 : 365;
        }

        public static int GetDaysOfMonth(int iYear, int month)
        {
            var days = 0;
            switch (month)
            {
                case 1:
                    days = 31;
                    break;
                case 2:
                    days = IsRuYear(iYear) ? 29 : 28;
                    break;
                case 3:
                    days = 31;
                    break;
                case 4:
                    days = 30;
                    break;
                case 5:
                    days = 31;
                    break;
                case 6:
                    days = 30;
                    break;
                case 7:
                    days = 31;
                    break;
                case 8:
                    days = 31;
                    break;
                case 9:
                    days = 30;
                    break;
                case 10:
                    days = 31;
                    break;
                case 11:
                    days = 30;
                    break;
                case 12:
                    days = 31;
                    break;
            }

            return days;
        }

        public static int GetDaysOfMonth(DateTime dt)
        {
            //--------------------------------//
            //--从dt中取得当前的年，月信息  --//
            //--------------------------------//
            int days = 0;
            int year = dt.Year;
            int month = dt.Month;

            //--利用年月信息，得到当前月的天数信息。
            switch (month)
            {
                case 1:
                    days = 31;
                    break;
                case 2:
                    days = IsRuYear(year) ? 29 : 28;
                    break;
                case 3:
                    days = 31;
                    break;
                case 4:
                    days = 30;
                    break;
                case 5:
                    days = 31;
                    break;
                case 6:
                    days = 30;
                    break;
                case 7:
                    days = 31;
                    break;
                case 8:
                    days = 31;
                    break;
                case 9:
                    days = 30;
                    break;
                case 10:
                    days = 31;
                    break;
                case 11:
                    days = 30;
                    break;
                case 12:
                    days = 31;
                    break;
            }
            return days;
        }

        public static string GetWeekNameOfDay(DateTime dt)
        {
            string week = string.Empty;
            switch (dt.DayOfWeek)
            {
                case DayOfWeek.Monday:
                    week = "星期一";
                    break;
                case DayOfWeek.Tuesday:
                    week = "星期二";
                    break;
                case DayOfWeek.Wednesday:
                    week = "星期三";
                    break;
                case DayOfWeek.Thursday:
                    week = "星期四";
                    break;
                case DayOfWeek.Friday:
                    week = "星期五";
                    break;
                case DayOfWeek.Saturday:
                    week = "星期六";
                    break;
                case DayOfWeek.Sunday:
                    week = "星期日";
                    break;
            }
            return week;
        }

        public static int GetWeekNumberOfDay(DateTime dt)
        {
            int week = 0;
            switch (dt.DayOfWeek)
            {
                case DayOfWeek.Monday:
                    week = 1;
                    break;
                case DayOfWeek.Tuesday:
                    week = 2;
                    break;
                case DayOfWeek.Wednesday:
                    week = 3;
                    break;
                case DayOfWeek.Thursday:
                    week = 4;
                    break;
                case DayOfWeek.Friday:
                    week = 5;
                    break;
                case DayOfWeek.Saturday:
                    week = 6;
                    break;
                case DayOfWeek.Sunday:
                    week = 7;
                    break;
            }
            return week;
        }

        public static void WeekRange(int year, int weekOrder, ref DateTime firstDate, ref DateTime lastDate)
        {
            //当年的第一天
            var firstDay = new DateTime(year, 1, 1);

            //当年的第一天是星期几
            int firstOfWeek = Convert.ToInt32(firstDay.DayOfWeek);

            //计算当年第一周的起止日期，可能跨年
            int dayDiff = (-1) * firstOfWeek + 1;
            int dayAdd = 7 - firstOfWeek;

            firstDate = firstDay.AddDays(dayDiff).Date;
            lastDate = firstDay.AddDays(dayAdd).Date;

            //如果不是要求计算第一周
            if (weekOrder != 1)
            {
                int addDays = (weekOrder - 1) * 7;
                firstDate = firstDate.AddDays(addDays);
                lastDate = lastDate.AddDays(addDays);
            }
        }

        public static int DiffDays(DateTime dtfrm, DateTime dtto)
        {
            TimeSpan tsDiffer = dtto.Date - dtfrm.Date;
            return tsDiffer.Days;
        }


        public static bool IsRuYear(int iYear)
        {
            //形式参数为年份
            //例如：2003
            int n = iYear;
            return (n % 400 == 0) || (n % 4 == 0 && n % 100 != 0);
        }


        public static DateTime AddWorkdays(this DateTime originalDate, int workDays)
        {
            DateTime tmpDate = originalDate;
            while (workDays > 0)
            {
                tmpDate = tmpDate.AddDays(1);
                if (tmpDate.DayOfWeek < DayOfWeek.Saturday &&
                    tmpDate.DayOfWeek > DayOfWeek.Sunday &&
                    tmpDate.IsHoliday())
                    workDays--;
            }
            return tmpDate;
        }

        public static bool IsHoliday(this DateTime originalDate)
        {
            // INSERT YOUR HOlIDAY-CODE HERE!
            //DateTime[] holidays =
            //   new DateTime[] { 
            //      new DateTime(2010,12,27),
            //      new DateTime(2010,12,28),
            //      new DateTime(2011,01,03),
            //      new DateTime(2011,01,12),
            //      new DateTime(2011,01,13)
            //    };

            return false;
        }

        public static DateTime AddWorkingDays(DateTime specificDate,
                                      int workingDaysToAdd)
        {
            int completeWeeks = workingDaysToAdd / 5;
            DateTime date = specificDate.AddDays(completeWeeks * 7);
            workingDaysToAdd = workingDaysToAdd % 5;
            for (int i = 0; i < workingDaysToAdd; i++)
            {
                date = date.AddDays(1);
                while (!IsWeekDayCheck(date))
                {
                    date = date.AddDays(1);
                }
            }
            return date;
        }

        private static bool IsWeekDayCheck(DateTime date)
        {
            DayOfWeek day = date.DayOfWeek;
            return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday;
        }


        public static DateTime AddBusinessDays(DateTime date, int days)
        {
            if (days == 0) return date;

            if (date.DayOfWeek == DayOfWeek.Saturday)
            {
                date = date.AddDays(2);
                days -= 1;
            }
            else if (date.DayOfWeek == DayOfWeek.Sunday)
            {
                date = date.AddDays(1);
                days -= 1;
            }

            date = date.AddDays(days / 5 * 7);
            int extraDays = days % 5;

            if ((int)date.DayOfWeek + extraDays > 5)
            {
                extraDays += 2;
            }

            return date.AddDays(extraDays);

        }

        public static int GetBusinessDays(DateTime start, DateTime end)
        {
            if (start.DayOfWeek == DayOfWeek.Saturday)
            {
                start = start.AddDays(2);
            }
            else if (start.DayOfWeek == DayOfWeek.Sunday)
            {
                start = start.AddDays(1);
            }

            if (end.DayOfWeek == DayOfWeek.Saturday)
            {
                end = end.AddDays(-1);
            }
            else if (end.DayOfWeek == DayOfWeek.Sunday)
            {
                end = end.AddDays(-2);
            }

            int diff = (int)end.Subtract(start).TotalDays;

            int result = diff / 7 * 5 + diff % 7;

            return end.DayOfWeek < start.DayOfWeek ? result - 2 : result;
        }
        #endregion

    }
}
